/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.nodes; import java.beans.Beans; import java.beans.PropertyEditor; import java.lang.reflect.*; import org.openide.util.NbBundle; /** Support class for <code>Node.Property</code>. * * @see Node.Property * @author Jan Jancura, Jaroslav Tulach, Ian Formanek * @version 0.21, Mar 24, 1998 */ public abstract class PropertySupport extends Node.Property { /** flag whether the property is readable */ private boolean canR; /** flag whether the property is writable */ private boolean canW; /** Constructs a new support. * @param name the name of the property * @param type the class type of the property * @param displayName the display name of the property * @param canR whether the property is readable * @param canW whether the property is writable */ public PropertySupport(String name, Class type, String displayName, String shortDescription, boolean canR, boolean canW) { super(type); this.setName(name); setDisplayName(displayName); setShortDescription(shortDescription); this.canR = canR; this.canW = canW; } /* Can read the value of the property. * Returns the value passed into constructor. * @return <CODE>true</CODE> if the read of the value is supported */ public boolean canRead () { return canR; } /* Can write the value of the property. * Returns the value passed into constructor. * @return <CODE>true</CODE> if the read of the value is supported */ public boolean canWrite () { return canW; } /** Support for properties from Java Reflection. */ public static class Reflection extends Node.Property { /** Instance of a bean. */ protected Object instance; /** setter method */ private Method setter; /** getter method */ private Method getter; /** class of property editor */ private Class propertyEditorClass; /** Create a support with method objects specified. * The methods must be public. * @param instance (Bean) object to work on * @param valueType type of the property * @param getter getter method, can be <code>null</code> * @param setter setter method, can be <code>null</code> * @throws IllegalArgumentException if the methods are not public */ public Reflection (Object instance, Class valueType, Method getter, Method setter) { super (valueType); if (getter != null && ! Modifier.isPublic (getter.getModifiers ())) throw new IllegalArgumentException ("Cannot use a non-public getter " + getter); // NOI18N if (setter != null && ! Modifier.isPublic (setter.getModifiers ())) throw new IllegalArgumentException ("Cannot use a non-public setter " + setter); // NOI18N this.instance = instance; this.setter = setter; this.getter = getter; } /** Create a support with methods specified by name. * The instance class will be examined for the named methods. * But if the instance class is not public, the nearest public superclass * will be used instead, so that the getters and setters remain accessible. * @param instance (Bean) object to work on * @param valueType type of the property * @param getter name of getter method, can be <code>null</code> * @param setter name of setter method, can be <code>null</code> * @exception NoSuchMethodException if the getter or setter methods cannot be found */ public Reflection (Object instance, Class valueType, String getter, String setter) throws NoSuchMethodException { this ( instance, valueType, // find the getter () getter == null ? null : findAccessibleClass (instance.getClass ()).getMethod ( getter, new Class[0] ), // find the setter (valueType) setter == null ? null : findAccessibleClass (instance.getClass ()).getMethod ( setter, new Class[] { valueType } ) ); } /** Find the nearest superclass (or same class) that is public to this one. */ private static Class findAccessibleClass (Class clazz) { if (Modifier.isPublic (clazz.getModifiers ())) { return clazz; } else { Class sup = clazz.getSuperclass (); if (sup == null) return Object.class; // handle interfaces return findAccessibleClass (sup); } } // [PENDING] should use Beans API in case there is overriding BeanInfo --jglick /** Create a support based on the property name. * The getter and setter methods are constructed by capitalizing the first * letter in the name of propety and prefixing it with <code>get</code> and * <code>set</code>, respectively. * * @param instance object to work on * @param valueType type of the property * @param property name of property * @exception NoSuchMethodException if the getter or setter methods cannot be found */ public Reflection (Object instance, Class valueType, String property) throws NoSuchMethodException { this ( instance, valueType, firstLetterToUpperCase (property, "get"), // NOI18N firstLetterToUpperCase (property, "set") // NOI18N ); } /** Helper method to convert the first letter of a string to uppercase. * And prefix the string with some next string. */ private static String firstLetterToUpperCase (String s, String pref) { switch (s.length ()) { case 0: return pref; case 1: return pref + Character.toUpperCase (s.charAt (0)); default: return pref + Character.toUpperCase (s.charAt (0)) + s.substring (1); } } /* Can read the value of the property. * @return <CODE>true</CODE> if the read of the value is supported */ public boolean canRead () { return getter != null; } /* Getter for the value. * @return the value of the property * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public Object getValue () throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (getter == null) throw new IllegalAccessException (); Object valideInstance = Beans.getInstanceOf (instance, getter.getDeclaringClass()); return getter.invoke (valideInstance, new Object [0]); } /* Can write the value of the property. * @return <CODE>true</CODE> if the read of the value is supported */ public boolean canWrite () { return setter != null; } /* Setter for the value. * @param val the value of the property * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public void setValue (Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (setter == null) throw new IllegalAccessException (); Object valideInstance = Beans.getInstanceOf (instance, setter.getDeclaringClass()); setter.invoke (valideInstance, new Object [] {val}); } /* Returns property editor for this property. * @return the property editor or <CODE>null</CODE> if there should not be * any editor. */ public PropertyEditor getPropertyEditor () { if (propertyEditorClass != null) try { return (PropertyEditor) propertyEditorClass.newInstance (); } catch (InstantiationException ex) { } catch (IllegalAccessException iex) { } return super.getPropertyEditor (); } /** Set the property editor explicitly. * @param clazz class type of the property editor */ public void setPropertyEditorClass (Class clazz) { propertyEditorClass = clazz; } } /** A simple read/write property. * Subclasses should implement * {@link #getValue} and {@link #setValue}. */ public static abstract class ReadWrite extends PropertySupport { /** Construct a new support. * @param name the name of the property * @param type the class type of the property * @param displayName the display name of the property * @param shortDescription a short description of the property */ public ReadWrite(String name, Class type, String displayName, String shortDescription) { super(name, type, displayName, shortDescription, true, true); } } /** A simple read-only property. * Subclasses should implement {@link #getValue}. */ public static abstract class ReadOnly extends PropertySupport { /** Construct a new support. * @param name the name of the property * @param type the class type of the property * @param displayName the display name of the property * @param shortDescription a short description of the property */ public ReadOnly(String name, Class type, String displayName, String shortDescription) { super(name, type, displayName, shortDescription, true, false); } /* Setter for the value. * @param val the value of the property * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public void setValue (Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { throw new IllegalAccessException("Cannot write to ReadOnly property"); // NOI18N } } /** A simple write-only property. * Subclasses should implement {@link #setValue}. */ public static abstract class WriteOnly extends PropertySupport { /** Construct a new support. * @param name the name of the property * @param type the class type of the property * @param displayName the display name of the property * @param shortDescription a short description of the property */ public WriteOnly(String name, Class type, String displayName, String shortDescription) { super(name, type, displayName, shortDescription, false, true); } /* Getter for the value. * @return the value of the property * @exception IllegalAccessException cannot access the called method * @exception IllegalArgumentException wrong argument * @exception InvocationTargetException an exception during invocation */ public Object getValue () throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { throw new IllegalAccessException("Cannod read from WriteOnly property"); // NOI18N } } /** Support for the name property of a node. Delegates {@link #setValue} and {@link #getValue} * to {@link Node#setName} and {@link Node#getName}. * <p>(Final only for performance, can be unfinaled if desired). */ public static final class Name extends PropertySupport { /** The node to which we delegate the work. */ private final Node node; /** Create the name property for a node with the standard name and hint. * @param node the node */ public Name (final Node node) { this(node, NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardName"), NbBundle.getBundle(PropertySupport.class).getString("CTL_StandardHint")); } /** Create the name property for a node. * @param node the node * @param propName name of the "name" property * @param hint hint message for the "name" property */ public Name (final Node node, final String propName, final String hint) { super(Node.PROP_NAME, String.class, propName, hint, true, node.canRename()); this.node = node; } /* Getter for the value. Delegates to Node.getName(). * @return the name */ public Object getValue () throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { return node.getName(); } /* Setter for the value. Delegates to Node.setName(). * @param val new name */ public void setValue (Object val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!(val instanceof String)) throw new IllegalAccessException (); node.setName((String)val); } } // end of Name inner class } /* * Log * 9 Gandalf 1.8 1/12/00 Jesse Glick NOI18N * 8 Gandalf 1.7 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 7 Gandalf 1.6 7/12/99 Jesse Glick PropertySupport.Reflection * now correctly handles the case where a non-public instance class is * specified, but the desired getters/setters are publically declared in a * public superclass. E.g. DefaultDataObject.getHelpCtx. Similarly done * for BeanNode a while back. * 6 Gandalf 1.5 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 5 Gandalf 1.4 4/7/99 Jesse Glick [JavaDoc] * 4 Gandalf 1.3 3/17/99 Jesse Glick [JavaDoc] * 3 Gandalf 1.2 3/17/99 Jesse Glick [JavaDoc] * 2 Gandalf 1.1 2/3/99 David Simonek * 1 Gandalf 1.0 1/5/99 Ian Formanek * $ * Beta Change History: * 0 Tuborg 0.12 --/--/98 Jaroslav Tulach More public setters * 0 Tuborg 0.13 --/--/98 Jan Jancura equals method removed * 0 Tuborg 0.20 --/--/98 Jan Formanek complex changes * 0 Tuborg 0.21 --/--/98 Jan Formanek {Hanz} expert flag removed */